package com.dm.cloud.tkmybatis.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.dm.cloud.core.annotation.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.dm.cloud.basepo.po.BasePo;
import com.dm.cloud.core.enums.LinkedEnum;
import com.dm.cloud.core.exception.CustomException;
import com.dm.cloud.core.mode.PageList;
import com.dm.cloud.core.mode.PaginationParam;
import com.dm.cloud.core.mode.SearchRequestPage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.util.Sqls;

import javax.persistence.Id;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 基础server,常用基本数据库操作
 *
 * @param <P>
 * @param <T>
 */
public interface BaseEntityService<P extends SearchRequestPage, T extends BasePo> {

    final static String SPLIT = ",";

    /**
     * 获取直接操作数据库接口
     *
     * @return
     */
    BaseMapper<T> getMapper();

    /**
     * 包装返回实体
     *
     * @param entity
     * @return
     */
    default T wrapperEntity(T entity) {
        return entity;
    }

    /**
     * 根据id查询记录
     *
     * @param id
     * @return
     */
    default T selectOne(String id) {
        T t = getMapper().selectByPrimaryKey(id);
        if (ObjectUtil.isEmpty(t)) {
            throw new CustomException("数据不存在");
        }
        processAfterOperation(t, BaseOperationEnum.SELECT);
        return wrapperEntity(t);
    }


    /**
     * 根据条件查询唯一字段
     *
     * @param example
     * @return
     */
    default T selectOne(Example example) {
        T t = getMapper().selectOneByExample(example);
        processAfterOperation(t, BaseOperationEnum.SELECT);
        return t;
    }

    /**
     * 根据指定字段查询唯一记录
     *
     * @param column 字段
     * @param value  字段对应的值
     * @return
     */
    default T selectOne(String column, Object value) {
        List<T> list = list(column, value);

        if (list.isEmpty()) {
            return null;
        }
        return wrapperEntity(list.get(0));
    }

    /**
     * 根据ID查询所有数据
     *
     * @param ids
     * @return
     */
    default List<T> selectByIds(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new CustomException("需查询的ID不能为空！");
        }
        Example example = Example.builder(getPoEntity()).andWhere(Sqls.custom().andIn("id", ids)).build();
        List<T> list = getMapper().selectByExample(example);
        processBatchAfterOperation(list, BaseOperationEnum.SELECT);
        return list;
    }


    /**
     * 分页
     *
     * @param pageParam
     * @return
     */
    default PageList<T> page(P pageParam) {
        return page(pageParam, null);
    }


    /**
     * 获取泛型T的class
     *
     * @return
     */
    default Class<T> getPoEntity() {
        Class<T> entityClass = (Class<T>) ((ParameterizedTypeImpl) ((Class) getClass().getGenericInterfaces()[0]).getGenericInterfaces()[0]).getActualTypeArguments()[1];
        return entityClass;
    }

    /**
     * 分页，指定查询条件即忽略扩展的条件
     *
     * @param pageParam
     * @param example   指定参数
     * @return
     */
    default PageList<T> page(P pageParam, Example example) {

        //如果exampl是空，则创建
        if (example == null) {
            example = Example.builder(getPoEntity()).build();
        }

        buildWhere(pageParam, example);
        Example finalExample = example;
        //设置分页字段
        PageInfo<T> pageInfo = PageHelper
                .startPage(pageParam.getPageParam().getPage(), pageParam.getPageParam().getPageSize())
                .doSelectPageInfo(() -> {
                            getMapper().selectByExample(finalExample);
                        }
                );
        PageList<T> re = new PageList<T>();
        re.setPageParam(PaginationParam.builder().page(pageInfo.getPageNum()).pageSize(pageInfo.getPageSize()).totalCount(pageInfo.getTotal()).build());
        List<T> list = pageInfo.getList();
        processBatchAfterOperation(list, BaseOperationEnum.SELECT);
        re.setData(list);
        return re;
    }


    /**
     * 抽象查询条件
     *
     * @param pageParam 查询条件
     * @return
     */
    default void buildWhere(P pageParam, Example example) {

        Example.Criteria criteria = example.createCriteria();
        Object param = pageParam.getSearchParam();
        //条件的值
        Field[] fields = param == null ? new Field[]{} : ReflectUtil.getFields(param.getClass());
//        排序算法，老本本废弃
//        OrderAlgorithm orderAlgorithm=new OrderAlgorithm();

        Arrays.stream(fields).filter(field -> {
            if (field.isAnnotationPresent(Query.class)) {
                Query query = field.getAnnotation(Query.class);
                return query.where();
            }
            return true;
        }).forEach(field -> {
            try {
                boolean flag;
                field.setAccessible(true);
                //列名
                String column;
                if (field.isAnnotationPresent(Query.class) && StringUtils.isNotBlank(field.getAnnotation(Query.class).column())) {
                    column = field.getAnnotation(Query.class).column();
                } else {
                    column = field.getName();
                }

                if (field.get(param) instanceof String) {
                    flag = StringUtils.isNoneBlank((String) field.get(param));
                } else {
                    flag = field.get(param) != null;
                }
                if (!flag) {
                    return;
                }

                //判断是否是模糊查询
                if (field.isAnnotationPresent(Query.class)) {
                    Object value = field.get(param);
                    if (ObjectUtil.isEmpty(value)) {
                        return;
                    }
                    switch (field.getAnnotation(Query.class).value()) {
                        case LIKE:
                            String likeValue = String.valueOf(field.get(param));

                            if (likeValue.contains("%")) {
                                likeValue = likeValue.replace("%", "\\%");
                            }

                            if (likeValue.contains("_")) {
                                likeValue = likeValue.replace("_", "\\_");
                            }
                            criteria.andLike(column, "%" + likeValue + "%");
                            break;
                        case IN:
                            if (value instanceof List) {
                                criteria.andIn(column, (List) value);
                            } else if (value instanceof String) {
                                String[] split = ((String) value).split(SPLIT);
                                List<String> list = Arrays.asList(split);
                                criteria.andIn(column, list);
                            }
                            break;
                        case GT:
                            criteria.andGreaterThan(column, field.get(param));
                            break;
                        case GE:
                            criteria.andGreaterThanOrEqualTo(column, field.get(param));
                            break;
                        case LT:
                            criteria.andLessThan(column, field.get(param));
                            break;
                        case LE:
                            criteria.andLessThanOrEqualTo(column, field.get(param));
                            break;
                        case BWT:
                            Object values = field.get(param);
                            if (values instanceof List) {
                                List lst = (List) values;
                                if (lst.size() == 2) {
                                    criteria.andBetween(column, lst.get(0), lst.get(1));
                                } else if (lst.size() == 1) {
                                    criteria.andGreaterThan(column, lst.get(0));
                                }
                            }
                            break;
                        default:
                            criteria.andEqualTo(column, field.get(param));
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
        Example.Criteria criteria2 = example.and();
        Arrays.stream(fields).filter(field -> {
            if (field.isAnnotationPresent(MultiQuery.class)) {
                MultiQuery query = field.getAnnotation(MultiQuery.class);
                return query.where();
            }
            return false;
        }).forEach(field -> {
            try {
                boolean flag;
                field.setAccessible(true);
                //列名
                String[] columns;
                if (field.isAnnotationPresent(MultiQuery.class) && !ArrayUtil.isEmpty(field.getAnnotation(MultiQuery.class).columns())) {
                    columns = field.getAnnotation(MultiQuery.class).columns();
                } else {
                    return;
                }

                if (field.get(param) instanceof String) {
                    flag = StringUtils.isNoneBlank((String) field.get(param));
                } else {
                    flag = field.get(param) != null;
                }
                if (!flag) {
                    return;
                }

                //判断是否是模糊查询
                Object value = field.get(param);
                if (ObjectUtil.isEmpty(value)) {
                    return;
                }
                MultiQuery multiQuery= field.getAnnotation(MultiQuery.class);
                switch (multiQuery.value()) {
                    case LIKE:
                        String likeValue = String.valueOf(field.get(param));
                        if (likeValue.contains("%")) {
                            likeValue = likeValue.replace("%", "\\%");
                        }

                        if (likeValue.contains("_")) {
                            likeValue = likeValue.replace("_", "\\_");
                        }
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andLike(column, "%" + likeValue + "%");
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orLike(column, "%" + likeValue + "%");
                            }
                        }
                        break;
                    case IN:
                        List list=null;
                        if (value instanceof List) {
                            list=(List) value;
                        } else if (value instanceof String) {
                            String[] split = ((String) value).split(SPLIT);
                            list = Arrays.asList(split);
                        }
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andIn(column, list);
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orIn(column, list);
                            }
                        }
                        break;
                    case GT:
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andGreaterThan(column, field.get(param));
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orGreaterThan(column, field.get(param));
                            }
                        }
                        break;
                    case GE:
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andGreaterThanOrEqualTo(column, field.get(param));
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orGreaterThanOrEqualTo(column, field.get(param));
                            }
                        }
                        break;
                    case LT:
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andLessThan(column, field.get(param));
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orLessThan(column, field.get(param));
                            }
                        }
                        break;
                    case LE:
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andLessThanOrEqualTo(column, field.get(param));
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orLessThanOrEqualTo(column, field.get(param));
                            }
                        }
                        break;
                    case BWT:
                        Object values = field.get(param);
                        if (values instanceof List) {
                            List lst = (List) values;
                            for (String column : columns) {
                                if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                    if (lst.size() == 2) {
                                        criteria2.andBetween(column, lst.get(0), lst.get(1));
                                    } else if (lst.size() == 1) {
                                        criteria2.andGreaterThan(column, lst.get(0));
                                    }
                                }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                    if (lst.size() == 2) {
                                        criteria2.orBetween(column, lst.get(0), lst.get(1));
                                    } else if (lst.size() == 1) {
                                        criteria2.orGreaterThan(column, lst.get(0));
                                    }
                                }
                            }

                        }
                        break;
                    default:
                        for (String column : columns) {
                            if(multiQuery.linkedEnum().equals(LinkedEnum.AND)){
                                criteria2.andEqualTo(column, field.get(param));
                            }else if(multiQuery.linkedEnum().equals(LinkedEnum.OR)){
                                criteria2.orEqualTo(column, field.get(param));
                            }
                        }
                        break;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });

//        String orderStr = orderAlgorithm.getOrderStr();
//        if(StrUtil.isNotEmpty(orderStr))example.setOrderByClause(orderStr);

        List<String> sorts = pageParam.getSort();
        if (sorts != null && !sorts.isEmpty()) {
            example.setOrderByClause(String.join(",", sorts));
        }
    }

    /**
     * 操作前处理
     *
     * @param entity        前端传递的对象
     * @param operationEnum 操作类型
     * @throws CustomException 阻止程序继续执行或回滚事务
     */
    default void processBeforeOperation(T entity, BaseOperationEnum operationEnum) throws CustomException {
    }

    /**
     * 操作后续处理
     *
     * @param entity
     * @param operationEnum 操作类型
     * @throws CustomException 阻止程序继续执行或回滚事务
     */
    default void processAfterOperation(T entity, BaseOperationEnum operationEnum) throws CustomException {
    }


    /**
     * 保存数据
     *
     * @param entity
     * @return
     * @throws CustomException 业务异常
     */
    @Transactional(rollbackFor = Exception.class)
    default Integer insert(T entity) throws CustomException {
        //保存前处理
        processBeforeOperation(entity, BaseOperationEnum.INSERT);

        //校验唯一索引
        checkUniqueField(entity, false);
//        try {
            //保存
            Integer result = getMapper().insertSelective(entity);
            //保存失败
            if (result == null || result < 1) {
                throw new CustomException("保存失败");
            }

            //保存缓存字段
            refreshCacheFields(entity, BaseOperationEnum.INSERT);
            //保存后处理
            processAfterOperation(entity, BaseOperationEnum.INSERT);

            return result;
//        }catch (Exception e){
//            throw new CustomException("保存失败");
//        }

    }

    /**
     * 刷新对应字段的缓存
     * 此处可拓展缓存,但是无法保证于数据库同步
     *
     * @param entity
     * @param operationEnum 操作类型
     */
    default void refreshCacheFields(T entity, BaseOperationEnum operationEnum) {


    }


    /**
     * 保存数据
     *
     * @param entities
     * @return
     * @throws CustomException 业务异常
     */
    @Transactional(rollbackFor = Exception.class)
    default Integer insertBatch(List<T> entities) throws CustomException {

        //保存
        Integer result = getMapper().insertList(entities);

        //保存缓存
        entities.stream().forEach(entity -> {
            //保存缓存字段
            refreshCacheFields(entity, BaseOperationEnum.INSERT);
        });

        //保存失败
        if (result == null || result < 1) {
            throw new CustomException("保存失败");
        }
        return result;
    }

    /**
     * 更新数据
     *
     * @param entity
     * @return
     * @throws CustomException 业务异常
     */
    @Transactional(rollbackFor = Exception.class)
    default Integer update(T entity) throws CustomException {
        //更新前处理
        processBeforeOperation(entity, BaseOperationEnum.UPDATE);
        //校验唯一索引
        checkUniqueField(entity, true);
        //更新
        Example.Builder builder = Example.builder(getPoEntity());
        checUpdateField(entity, builder);
        Integer result = getMapper().updateByExampleSelective(entity, builder.build());
        //更新失败
        if (result == null || result < 1) {
            throw new CustomException("更新失败");
        }

        //保存缓存字段
        refreshCacheFields(entity, BaseOperationEnum.UPDATE);
        //更新后处理
        processAfterOperation(entity, BaseOperationEnum.UPDATE);
        return result;
    }

    /**
     * 批量更新对象
     *
     * @param entitys
     * @return
     */
    default int updateBath(List<T> entitys) {
        //更新前处理
        processBatchBeforeOperation(entitys, BaseOperationEnum.UPDATE);
        int result = 0;
        for (T entity : entitys) {
            //更新
            Example.Builder builder = Example.builder(getPoEntity());
            //校验唯一索引
            checkUniqueField(entity, true);
            checUpdateField(entity, builder);
            result += getMapper().updateByExampleSelective(entity, builder.build());
            //保存缓存字段
            refreshCacheFields(entity, BaseOperationEnum.UPDATE);
        }
        //更新后处理
        processBatchAfterOperation(entitys, BaseOperationEnum.UPDATE);
        return result;
    }

    /**
     * 根据id更新指定值
     *
     * @param map
     * @param id
     * @return
     */
    default Integer updateFieldsById(Map<String, Object> map, String id) {
        map.put("id", id);
        T entity = BeanUtil.toBean(map, getPoEntity());
        return getMapper().updateByPrimaryKeySelective(entity);
    }


    /**
     * 根据id批量更新指定值
     *
     * @param map
     * @param ids
     * @return
     */
    default Integer updateBatchFieldsById(Map<String, Object> map, List<String> ids) {
        int x = 0;
        for (String id : ids) {
            x += updateFieldsById(map, id);
        }
        return x;
    }


    /**
     * 删除
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default Integer deleteById(Serializable id) {
        T t = getById(id);
        if (t == null) {
//            throw new CustomException("数据"+id+"不存在，请确认是否已删除");
            return 0;
        }
        //删除前处理
        processBeforeOperation(t, BaseOperationEnum.DELETE);
        Integer result = getMapper().deleteByPrimaryKey(id);

        //删除失败
        if (result == null || result < 1) {
            throw new CustomException("删除失败");
        }

        //保存缓存字段
        refreshCacheFields(t, BaseOperationEnum.DELETE);

        //删除后处理
        processAfterOperation(t, BaseOperationEnum.DELETE);
        return result;
    }

    /**
     * 批处理操作前处理
     *
     * @param entities      前端传递的对象
     * @param operationEnum 操作类型
     * @throws CustomException 阻止程序继续执行或回滚事务
     */
    default void processBatchBeforeOperation(List<T> entities, BaseOperationEnum operationEnum) throws CustomException {
        BaseOperationEnum onlyEnum = operationEnum;
        if (operationEnum.equals(BaseOperationEnum.DELETE_BATCH)) {
            onlyEnum = BaseOperationEnum.DELETE;
        }
        for (T entity : entities) {
            processBeforeOperation(entity, onlyEnum);
        }
    }

    /**
     * 批处理操作后续处理
     *
     * @param entities
     * @param operationEnum 操作类型
     * @throws CustomException 阻止程序继续执行或回滚事务
     */
    default void processBatchAfterOperation(List<T> entities, BaseOperationEnum operationEnum) throws CustomException {
        BaseOperationEnum onlyEnum = operationEnum;
        if (operationEnum.equals(BaseOperationEnum.DELETE_BATCH)) {
            onlyEnum = BaseOperationEnum.DELETE;
        }
        for (T entity : entities) {
            processAfterOperation(entity, onlyEnum);
        }
    }

    /**
     * 批量删除
     *
     * @param idList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default int deleteByIds(Collection<? extends Serializable> idList) {
        Example example = Example.builder(getPoEntity()).andWhere(Sqls.custom().andIn("id", idList)).build();
        List<T> list = getMapper().selectByExample(example);
        if (list == null || list.isEmpty()) {
            return 0;
        }
        processBatchBeforeOperation(list, BaseOperationEnum.DELETE_BATCH);
        int i = getMapper().deleteByExample(example);
        if (i > 0) {
            //刷新缓存
            //保存缓存
            list.stream().forEach(entity -> {
                //保存缓存字段
                refreshCacheFields(entity, BaseOperationEnum.DELETE_BATCH);
            });
            processBatchAfterOperation(list, BaseOperationEnum.DELETE_BATCH);
        }
        return i;
    }

    /**
     * 删除
     *
     * @param example 条件
     */
    @Transactional(rollbackFor = Exception.class)
    default int delete(Example example) {
        List<T> list = getMapper().selectByExample(example);
        if (list == null || list.isEmpty()) {
            return 0;
        }
        processBatchBeforeOperation(list, BaseOperationEnum.DELETE_BATCH);
        getMapper().deleteByExample(example);
        int i = getMapper().deleteByExample(example);
        if (i > 0) {
            //刷新缓存
            //保存缓存
            list.stream().forEach(entity -> {
                //保存缓存字段
                refreshCacheFields(entity, BaseOperationEnum.DELETE_BATCH);
            });
            processBatchAfterOperation(list, BaseOperationEnum.DELETE_BATCH);
        }
        return i;
    }


    /**
     * 校验必填字段
     *
     * @param entity
     * @param builder
     */
    default void checUpdateField(T entity, Example.Builder builder) {
        Field[] allFields = ReflectUtil.getFields(entity.getClass());
        List<Field> updateMustFields = Arrays.stream(allFields).filter(field -> field.isAnnotationPresent(UpdateMust.class)).collect(Collectors.toList());
        if (!updateMustFields.isEmpty()) {
            for (Field field : updateMustFields) {
                try {
                    Object value = getFieldValue(entity, field);
                    if (value == null) {
                        String errMsg = field.getAnnotation(UpdateMust.class).errMsg();
                        throw new CustomException(StrUtil.isEmpty(errMsg) ? "修改时[" + field.getName() + "]字段为必填" : errMsg);
                    } else {
                        //如果没有指定列，默认是字段的驼峰转下划线
                        builder.andWhere(Sqls.custom().andEqualTo(field.getName(), value));
                    }
                } catch (Exception exception) {
                    if (exception instanceof CustomException) {
                        throw (CustomException) exception;
                    } else {
                        throw new CustomException("错误[" + field.getName() + "]字段内容错误");
                    }
                }
            }
        }
        Optional<Field> idFiledOptional = Arrays.stream(allFields).filter(field -> field.isAnnotationPresent(Id.class)).findFirst();
        //当不包含@Id是，忽略
        if (idFiledOptional.isPresent()) {
            Field idField = idFiledOptional.get();
            try {
                builder.andWhere(Sqls.custom().andEqualTo(idField.getName(), idField.get(entity)));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
//        CurrentUserService currUserService = ApplicationUtil.getBean(CurrentUserService.class);
//        entity.setUpdateUser(currUserService.uname());
//        entity.setUpdateTime(new Date());
    }

    /**
     * 校验唯一
     *
     * @param entity   实体对象
     * @param isUpdate 是否是更新
     */
    default void checkUniqueField(T entity, boolean isUpdate) {

        Field[] allFields = ReflectUtil.getFields(entity.getClass());

//        Optional<Field> idFiledOptional = Arrays.stream(allFields).filter(field -> field.isAnnotationPresent(Id.class)).findFirst();
        //当不包含@Id是，忽略

        //主键字段
        Field idField = null;
        Map<String, List<Field>> groupMap = new HashMap<>();
        Map<String, String> groupErr = new HashMap<>();
        //判断联合唯一索引
        for (Field field : allFields) {
            try {
                if (field.isAnnotationPresent(JointUnqiue.class) && ObjectUtil.isNotEmpty(getFieldValue(entity, field))) {
                    JointUnqiue jointUnique = field.getDeclaredAnnotation(JointUnqiue.class);
                    List<Field> listFeilds;
                    //组字段
                    if (groupMap.containsKey(jointUnique.group())) {
                        listFeilds = groupMap.get(jointUnique.group());
                    } else {
                        listFeilds = new ArrayList<>();
                        groupMap.put(jointUnique.group(), listFeilds);
                    }
                    listFeilds.add(field);
                    //组异常消息,只取第一个带有异常描述的
                    if (!groupErr.containsKey(jointUnique.group()) && StrUtil.isNotEmpty(jointUnique.code())) {
                        groupErr.put(jointUnique.group(), jointUnique.code());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (field.isAnnotationPresent(Id.class) && idField == null) {
                idField = field;
            }
        }

        if (idField != null) {
            idField.setAccessible(true);
        }
        if (!groupMap.isEmpty()) {
            for (String group : groupMap.keySet()) {
                Example.Builder builder = Example.builder(getPoEntity());
                Integer integer;
                List<Field> fields = groupMap.get(group);
                for (Field field : fields) {
                    try {
                        Object value = getFieldValue(entity, field);
                        if (ObjectUtil.isNotEmpty(value)) {
                            builder.andWhere(Sqls.custom().andEqualTo(field.getName(), value));
                        }
                    } catch (Exception e) {
                        break;
                    }
                }
                if (isUpdate) {
                    if (idField == null) {
                        throw new CustomException("修改时必须带上主键ID");
                    }
                    try {
                        builder.andWhere(Sqls.custom().andNotEqualTo(idField.getName(), idField.get(entity)));
                    } catch (Exception e) {
                        break;
                    }
                }
                integer = getMapper().selectCountByExample(builder.build());
                if (integer > 0) {
                    throw new CustomException(groupErr.containsKey(group) ? groupErr.get(group) : "数据重复");
                }
            }
        }
        //开始判断唯一索引
        if (idField == null) {
            return;
        }

        //判断单一索引
        for (Field field : allFields) {
            if (field.isAnnotationPresent(Unique.class)) {
                Unique unique = field.getDeclaredAnnotation(Unique.class);
                Example.Builder builder = Example.builder(getPoEntity());
                Integer integer;
                try {
                    Object value = getFieldValue(entity, field);
                    builder.andWhere(Sqls.custom().andEqualTo(field.getName(), value));
                    if (isUpdate) {
                        builder.andWhere(Sqls.custom().andNotEqualTo(idField.getName(), idField.get(entity)));
                    }
                    integer = getMapper().selectCountByExample(builder.build());
                } catch (Exception e) {
                    continue;
                }
                if (integer > 0) {
                    throw new CustomException(unique.code() + field.getName());
                }
            }
        }
    }

    /**
     * 获取属性值
     *
     * @param entity
     * @param field
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    default Object getFieldValue(T entity, Field field) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), entity.getClass());
        Method readMethod = propertyDescriptor.getReadMethod();
        return readMethod.invoke(entity);
    }

    /**
     * 根据指定字段查询对应的值
     *
     * @param column
     * @param value
     * @return
     */
    default List<T> list(String column, Object value) {
        Example example = Example.builder(getPoEntity()).andWhere(Sqls.custom().andEqualTo(column, value)).build();
        List<T> list = getMapper().selectByExample(example);
        processBatchAfterOperation(list, BaseOperationEnum.SELECT);
        return list;
    }

    /**
     * 查询数量
     *
     * @param example
     * @return
     */
    default Integer count(Example example) {
        return getMapper().selectCountByExample(example);
    }

    /**
     * 根据指定条件查询对应的记录
     *
     * @param example
     * @return
     */
    default List<T> list(Example example) {
        List<T> list = getMapper().selectByExample(example);
        processBatchAfterOperation(list, BaseOperationEnum.SELECT);
        return list;
    }

    /**
     * ResponseBean
     * 根据ID查询记录
     *
     * @param id
     * @return
     */
    default T getById(Serializable id) {
        T t = getMapper().selectByPrimaryKey(id);
        processAfterOperation(t, BaseOperationEnum.SELECT);
        return t;
    }

    /**
     * 查询所有
     *
     * @return
     */
    default List<T> findAll() {
        List<T> list = getMapper().selectAll();
        processBatchAfterOperation(list, BaseOperationEnum.SELECT);
        return list;
    }

    /**
     * 根据指定字段更新值
     *
     * @param id
     * @param column
     * @param value
     */
    default Integer updateColumn(String id, String column, Object value) {
        Map<String, Object> params = new HashMap<>(1);
        params.put(column, value);
        return updateFieldsById(params, id);
    }


    public enum BaseOperationEnum {

        /**
         * 插入操作枚举
         */
        INSERT,
        /**
         * 更新操作枚举
         */
        UPDATE,
        /**
         * 删除操作枚举
         */
        DELETE,
        /**
         * 批量删除操作枚举
         */
        DELETE_BATCH,
        /**
         * 查询
         */
        SELECT
    }
}
